package com.huawei.java.alogrithm;

import com.huawei.java.model.Graph;
import com.huawei.java.model.SiteNode;

import java.util.Comparator;
import java.util.Map;
import java.util.TreeSet;

public class OptimizeResult {
    /**
     * 我们把每次分配的结果进行再次分配，优先从权值小的边缘节点往权值大的边缘节点挪动，权值指的是当前边缘节点能给给多少用户分配，能分配到的用户越多，权值越大。
     * 这样我们就能尽可能的集中到权值比较大的边缘节点来。
     * 双指针调节结果
     *      如果head节点有剩余流量 就把tai节点用到的的流量往head挪
     *      如果head节点的流量不够装满tail的就把head拉满，更新流量，再head++
     *      如果head满了就head++, tail没了就tail--
     *
     * @param allocationMap 某个用户分配的结果
     */
    public void redistribution(Map<String, Integer> allocationMap, Graph graph) {
        SiteNode[] sortedSiteNodes = getSortedSiteNodes(allocationMap, graph);
        // 双指针调节结果
        int head = 0;
        int tail = sortedSiteNodes.length - 1;
        while (head != tail) {
            SiteNode target = sortedSiteNodes[head];
            SiteNode src = sortedSiteNodes[tail];
            int srcBandwidth = allocationMap.get(src.getName());
            int targetValidBandwidth = target.getCurrentBandwidth();
            if (targetValidBandwidth >= srcBandwidth) {
                target.setCurrentBandwidth(targetValidBandwidth - srcBandwidth);
                target.setUsed(true);
                src.setCurrentBandwidth(src.getCurrentBandwidth() + srcBandwidth);
                allocationMap.remove(src.getName());
                allocationMap.put(target.getName(), srcBandwidth + allocationMap.get(target.getName()));
                tail--;
                continue;
            }
            // 如果head节点没有那么多剩余流量了，那么我们就把head节点拉满,target可用流量为0
            // src节点可用流量增加targetValidBandwidth，还有剩余流量 /
            int surplusBandwidth = srcBandwidth - targetValidBandwidth;
            target.setCurrentBandwidth(0);
            target.setUsed(true);
            allocationMap.put(target.getName(), allocationMap.get(target.getName()) + targetValidBandwidth);
            src.setCurrentBandwidth(src.getCurrentBandwidth() + targetValidBandwidth);
            allocationMap.put(src.getName(), surplusBandwidth);
            head++;
        }
    }

    private SiteNode[] getSortedSiteNodes(Map<String, Integer> allocationMap, Graph graph) {
        TreeSet<SiteNode> siteNodes = new TreeSet<>(new Comparator<SiteNode>() {
            @Override
            public int compare(SiteNode one, SiteNode another) {
                if (one.getAvailableNum() > 0 && one.isUsed()) {
                    return -1;
                }
                if (another.getAvailableNum() > 0 && another.isUsed()) {
                    return 1;
                }
                int validNum = another.getAvailableNum() - one.getAvailableNum();
                if (validNum != 0) {
                    return validNum;
                }
                int result = another.getValidClient().size() - one.getValidClient().size();
                return result == 0 ? 1 : result;
            }
        });
        Map<String, SiteNode> siteIdMap = graph.getSiteIdMap();
        for (Map.Entry<String, Integer> entry : allocationMap.entrySet()) {
            siteNodes.add(siteIdMap.get(entry.getKey()));
        }
        SiteNode[] sortedSiteNodes = new SiteNode[siteNodes.size()];
        int index = 0;
        for (SiteNode siteNode : siteNodes) {
            sortedSiteNodes[index++] = siteNode;
        }
        return sortedSiteNodes;
    }
}
